//
// Created by 王一飞 on 2021/1/3.
//

#include <math.h>
#include <dirent.h>
#include <stdio.h>
#include "func.h"
#include <sys/stat.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <sys/ioctl.h>

extern int a_flag;
extern int l_flag;
extern int flag_of_mulDir;
extern struct winsize sz;
struct dirent **fileList;

int link_len;       // 链接数长度
int uname_len;      // 用户长度
int gname_len;      // 用户组长度
int size_len;       // 文件大小长度
int filename_len;   // 文件名的最大长度

void ls_file(char *fileName) {
    if (l_flag) {
        // strCnt(fileName);
        struct stat fileInfo;
        getFileInfo(fileName, &fileInfo);
    }
    printf("%s\n", fileName);
}

void ls_all_file(char *dirName) {
    int cnt;
    cnt = scandir(dirName, &fileList, NULL, alphasort);
    if (cnt == -1) {
        perror(dirName);
        // printf("ls : %s: No such file or directory\n", dirName);
    } else {
        // 获取最大的长度
        for (int i = 0; i < cnt; i++) {
            char allDir[2048];
            getAllDir(dirName, fileList[i], allDir);
            strCnt(allDir);
        }
        char **aryFileName;
        if (a_flag) {
            aryFileName = (char **)calloc(512, sizeof(char *));
            for (int i = 0; i < 512; i++) {
                aryFileName[i] = (char *)calloc(512, sizeof(char));
            }
        }
        for (int i = 0; i < cnt; i++) {
            // -a 对应
            if (fileList[i]->d_name[0] == '.' && !a_flag) {
                continue;
            }
            // -l的换行对应
            if (l_flag) {
                char allDir[2048];
                i && printf("\n");
                getAllDir(dirName, fileList[i], allDir);
                // getFileInfo(allDir, &fileInfo);
                struct stat fileInfo;
                getFileInfo(allDir, &fileInfo);
                printf("%s\t", fileList[i]->d_name);
            } else {                    
                // strcpy(aryFileName[i], fileList[i]->d_name);
                aryFileName[i] = strdup(fileList[i]->d_name);
                if (strlen(fileList[i]->d_name) > filename_len) {
                    filename_len = strlen(fileList[i]->d_name);
                }
                print_col(aryFileName, cnt);
            }
            
            // if (l_flag)
            //     printf("\n");
            free(fileList[i]);
        }
        printf("\n");
        free(fileList);
    }
    link_len = 0;
    size_len = 0;
    uname_len = 0;
    gname_len = 0;
}

int getFileInfo(char *fileName, struct stat *fileInfo) {
    if (stat(fileName, fileInfo) < 0) {
        printf(RED("Error_getFileInfo, %s\n"), fileName);
        return -1;
    }
    // 输出文件类型
    if (S_ISDIR(fileInfo->st_mode))
        printf("d");
    else if (S_ISREG(fileInfo->st_mode))
        printf("-");
    else if (S_ISCHR(fileInfo->st_mode))
        printf("c");
    else if (S_ISBLK(fileInfo->st_mode))
        printf("b");
    else if (S_ISFIFO(fileInfo->st_mode))
        printf("p");
    else if (S_ISLNK(fileInfo->st_mode))
        printf("l");
    else if (S_ISSOCK(fileInfo->st_mode))
        printf("s");

    // 输出权限字符串
    accessChange(fileInfo);

    // 输出链接数
    // printf("%d ", fileInfo->st_nlink);
    myPrint(fileInfo->st_nlink, PRINT_LINK);

    // 输出用户
    // printf("%s ", getpwuid(fileInfo->st_uid)->pw_name);
    myPrintForString(getpwuid(fileInfo->st_uid)->pw_name, PRINT_USER);

    // 输出用户组
    // printf("%s ", getgrgid(fileInfo->st_gid)->gr_name);
    myPrintForString(getgrgid(fileInfo->st_gid)->gr_name, PRINT_GROUP);

    // 输出size
    // printf("%d ", fileInfo->st_size);
    myPrint(fileInfo->st_size, PRINT_SIZE);

    struct tm t;
    char date_time[64];
    // strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&fileInfo->st_ctim.tv_sec, &t));
    strftime(date_time, sizeof(date_time), "%b %d %H:%M", localtime_r(&fileInfo->st_ctim.tv_sec, &t));
    printf("%s ", date_time);

    return 0;
}

int getAllDir(char *dirName, struct dirent *entry, char *allDir) {
    strcpy(allDir, dirName);
    if (dirName[strlen(dirName) - 1] != '/') {
        strcat(allDir, "/");
    }
    strcat(allDir, entry->d_name);
    return 0;
}

int accessChange(struct stat *fileInfo) {
    (fileInfo->st_mode & S_IRUSR) ? printf("r") : printf("-");
    (fileInfo->st_mode & S_IWUSR) ? printf("w") : printf("-");
    (fileInfo->st_mode & S_IXUSR) ? printf("x") : printf("-");
    (fileInfo->st_mode & S_IRGRP) ? printf("r") : printf("-");
    (fileInfo->st_mode & S_IWGRP) ? printf("w") : printf("-");
    (fileInfo->st_mode & S_IXGRP) ? printf("x") : printf("-");
    (fileInfo->st_mode & S_IROTH) ? printf("r") : printf("-");
    (fileInfo->st_mode & S_IWOTH) ? printf("w") : printf("-");
    (fileInfo->st_mode & S_IXOTH) ? printf("x ") : printf("- ");

    return 0;
}

void myPrint(int a, int type) {
    int tmp = a;
    int length = 0;
    while (tmp) {
        tmp /= 10;
        length++;
    }
    int maxLen = 0;
    if (type == PRINT_LINK)
        maxLen = link_len;
    else if (type == PRINT_SIZE)
        maxLen = size_len;
    if (length < maxLen) {
        if (length == 0) length++;
        for (int i = 0; i < maxLen - length; i++) {
            printf(" ");
        }
    }
    printf("%d ", a);
}

void myPrintForString(char *str, int type) {
    int length = strlen(str);
    int maxLen = 0;
    if (type == PRINT_USER)
        maxLen = uname_len;
    else if (type == PRINT_GROUP)
        maxLen = gname_len;
    if (length < maxLen) {
        if (length == 0) length++;
        for (int i = 0; i < maxLen - length; i++) {
            printf(" ");
        }
    }
    printf("%s ", str);
}

void strCnt(char *fileName) {
    struct stat st;
    if (stat(fileName, &st) < 0) {
        printf(RED("Error_strCnt, %s\n"), fileName);
        // return -1;
    }
    // 链接数长度
    int tmpLen = 0;
    int tmp = st.st_nlink;
    while (tmp) {
        tmp /= 10;
        tmpLen++;
    }
    if (link_len < tmpLen)
        link_len = tmpLen;
    // 用户长度
    char userName[1024];
    strcpy(userName, getpwuid(st.st_uid)->pw_name);
    tmpLen = strlen(userName);
    if (uname_len < tmpLen)
        uname_len = tmpLen;
    // 用户组长度
    tmpLen = strlen(getgrgid(st.st_gid)->gr_name);
    if (gname_len < tmpLen)
        gname_len = tmpLen;
    // 文件大小长度
    tmp = st.st_size;
    tmpLen = 0;
    while (tmp) {
        tmp /= 10;
        tmpLen++;
    }
    if (size_len < tmpLen)
        size_len = tmpLen;
}

void print_col(char **aryFileName, int fileCnt) {
    int col_cnt = ceil(((double)sz.ws_col / filename_len));
    int col_len = 0;
    while (col_len <= sz.ws_col) {
        if (!col_len) 
            col_cnt++;
        for (int i = 0; i < 512; i += col_cnt) {
            col_len += strlen(aryFileName[i]);
        }
    }
    int row_cnt = ceil(((double)fileCnt / col_cnt));
    for (int i = 0; i < row_cnt; i += col_cnt) {
        for (int j = i; j < col_cnt; j++) {
            if (j != i) {
                printf(" ");
            }
            printf("%s", aryFileName[j]);
        }
    }
}